#include "JsonPathFilterExpr.h"

#include "Log/Log.h"
#include "Poco/StringTokenizer.h"
#include "Poco/UUIDGenerator.h"
#include "Poco/UUID.h"

JsonPathFilterExpr::JsonPathFilterExpr(std::string strLeftLogic, std::string strExpr)
{
    m_stData.m_strLeftLogic = strLeftLogic;
    Poco::UUID uuid = Poco::UUIDGenerator::defaultGenerator().createRandom();
    m_strUUID = uuid.toString();
    m_bValid = Tokenization(strExpr);
}

JsonPathFilterExpr::JsonPathFilterExpr(const JsonPathFilterExpr& stExpr)
{
    m_stData = stExpr.m_stData;
    m_strUUID = stExpr.m_strUUID;
    m_bValid = stExpr.m_bValid;
    for (auto& it : stExpr.m_vectSubExpr)
    {
        m_vectSubExpr.push_back(new JsonPathFilterExpr(*it));
    }
}

JsonPathFilterExpr& JsonPathFilterExpr::operator=(const JsonPathFilterExpr& stExpr)
{
    if (this != &stExpr)
    {
        m_stData = stExpr.m_stData;
        m_strUUID = stExpr.m_strUUID;
        m_bValid = stExpr.m_bValid;
        for (auto& it : stExpr.m_vectSubExpr)
        {
            m_vectSubExpr.push_back(new JsonPathFilterExpr(*it));
        }
    }
    return *this;
}

JsonPathFilterExpr::~JsonPathFilterExpr()
{
    for (auto& it : m_vectSubExpr)
    {
        delete it;
        it = nullptr;
    }
    m_vectSubExpr.clear();
}

bool JsonPathFilterExpr::ExprResult(Poco::JSON::Object::Ptr pObj, bool bLeftResult)
{
    if (!m_stData.m_strLeftLogic.empty())
    {
        if (m_stData.m_strLeftLogic == "&&" && bLeftResult == false)
        {
            return false;
        }
        else if (m_stData.m_strLeftLogic == "||" && bLeftResult == true)
        {
            return true;
        }
    }
    bool bCurResult = false;
    if (m_vectSubExpr.empty())
    {
        Poco::Dynamic::Var var = pObj->get(m_stData.m_strKey);
        if (pObj->has(m_stData.m_strKey) == false)
        {
            return false;
        }
        if (m_stData.m_eOperatorType == JsonPathFilterExprData::LOGIC_OPR_NO)
        {
            return true;
        }
        if (var.isArray())
        {
            return false;
        }
        else if (var.isBoolean())
        {
            bool bValue = var.convert<bool>();
            std::string strValLower = Poco::toLower(m_stData.m_strValue);
            bool bExprValue = (strValLower == "true");

            bCurResult = m_stData.DoLogic(bValue, bExprValue);
        }
        else if (var.type() == typeid(double))
        {
            double dValue = var.convert<double>();
            double dExprValue = atof(m_stData.m_strValue.c_str());

            bCurResult = m_stData.DoLogic(dValue, dExprValue);
        }
        else if (var.isSigned() || pObj->get(m_stData.m_strKey).isInteger())
        {
            int64_t iValue = pObj->get(m_stData.m_strKey).convert<int64_t>();
            int64_t iExprValue = atol(m_stData.m_strValue.c_str());

            bCurResult = m_stData.DoLogic(iValue, iExprValue);
        }
        else if (pObj->get(m_stData.m_strKey).isString())
        {
            std::string strValue = pObj->get(m_stData.m_strKey).convert<std::string>();

            bCurResult = m_stData.DoLogic(strValue, m_stData.m_strValue);
        }
        else
        {
            bCurResult = false; // 不支持的类型
            zlog.SError("not support type for [%s]\n", m_stData.m_strKey.c_str());
        }
    }
    else
    {
        for (auto& it : m_vectSubExpr)
        {
            bCurResult = it->ExprResult(pObj, bCurResult);
        }
    }
    if (!m_stData.m_strLeftLogic.empty())
    {
        if (m_stData.m_strLeftLogic == "&&")
        {
            return bLeftResult && bCurResult;
        }
        else if (m_stData.m_strLeftLogic == "||")
        {
            return bLeftResult || bCurResult;
        }
    }
    return bCurResult;
}

bool JsonPathFilterExpr::IsValid(bool bLeftExprRes)
{
    return m_bValid;
}

void JsonPathFilterExpr::PushSubExpr(JsonPathFilterExpr* pExpr)
{
    if (pExpr->IsValid() == false)
    {
        m_bValid = false;
    }
    if (m_bValid == false && m_vectSubExpr.empty())
    {
        m_bValid = pExpr->IsValid();
    }
    m_vectSubExpr.push_back(pExpr);
}

bool JsonPathFilterExpr::Tokenization(std::string strExpr)
{
    std::string strOperator;
    if (strExpr.find(">=") != std::string::npos) { m_stData.m_eOperatorType = JsonPathFilterExprData::LOGIC_OPR_GE; strOperator = ">="; }
    else if (strExpr.find("<=") != std::string::npos) { m_stData.m_eOperatorType = JsonPathFilterExprData::LOGIC_OPR_LE; strOperator = "<="; }
    else if (strExpr.find("==") != std::string::npos) { m_stData.m_eOperatorType = JsonPathFilterExprData::LOGIC_OPR_EQ; strOperator = "=="; }
    else if (strExpr.find("!=") != std::string::npos) { m_stData.m_eOperatorType = JsonPathFilterExprData::LOGIC_OPR_NE; strOperator = "!="; }
    else if (strExpr.find(">") != std::string::npos) { m_stData.m_eOperatorType = JsonPathFilterExprData::LOGIC_OPR_GT; strOperator = ">"; }
    else if (strExpr.find("<") != std::string::npos) { m_stData.m_eOperatorType = JsonPathFilterExprData::LOGIC_OPR_LT; strOperator = "<"; }
    else
    {
        while (!strExpr.empty() && (strExpr[0] == ' ' || strExpr[0] == '@' || strExpr[0] == '.')) strExpr.erase(0, 1);
        while (!strExpr.empty() && strExpr[strExpr.size() - 1] == ' ') strExpr.erase(strExpr.size() - 1, 1);
        m_stData.m_strKey = strExpr;
        return strExpr.empty() == false;
    }
    Poco::StringTokenizer tokenizer(strExpr, strOperator, Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
    if (tokenizer.count() != 2) return false;
    m_stData.m_strKey = tokenizer[0];
    m_stData.m_strValue = tokenizer[1];

    std::string& strKey = m_stData.m_strKey;
    while (!strKey.empty() && (strKey[0] == ' ' || strKey[0] == '@' || strKey[0] == '.')) strKey.erase(0, 1);
    while (!strKey.empty() && strKey[strKey.size() - 1] == ' ') strKey.erase(strKey.size() - 1, 1);

    std::string& strValue = m_stData.m_strValue;
    while (!strValue.empty() && (strValue[0] == ' ' || strValue[0] == '\'' || strValue[0] == '"')) strValue.erase(0, 1);
    while (!strValue.empty() && (strValue[strValue.size() - 1] == ' ' || strValue[strValue.size() - 1] == '\'' || strValue[strValue.size() - 1] == '"')) strValue.erase(strValue.size() - 1, 1);

    return true;
}

template<typename T>
bool JsonPathFilterExprData::DoLogic(T vl, T vr)
{
    switch (m_eOperatorType)
    {
    case LOGIC_OPR_GT: return vl > vr;
    case LOGIC_OPR_LT: return vl < vr;
    case LOGIC_OPR_EQ:
        if constexpr (std::is_same_v<T, std::string>) { return vl == vr; }
        else if (typeid(T) == typeid(double)) return std::abs(vl - vr) < 1e-9;
        else return vl == vr;
    case LOGIC_OPR_GE: return vl >= vr;
    case LOGIC_OPR_LE: return vl <= vr;
    case LOGIC_OPR_NE:
        if constexpr (std::is_same_v<T, std::string>) { return vl != vr; }
        else if (typeid(T) == typeid(double)) return std::abs(vl - vr) >= 1e-9;
        else return vl != vr;
    default: zlog.SError("operator type not set\n"); return false;
    }
    zlog.SError("operator type not set\n");
    return false;
}
